package com.easylinkin.linkappapi.meterbilling.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.common.utils.DateUtil;
import com.easylinkin.linkappapi.common.utils.excel.ExcelConstant;
import com.easylinkin.linkappapi.common.utils.excel.ExcelTools;
import com.easylinkin.linkappapi.common.utils.io.OutputStreamUtil;
import com.easylinkin.linkappapi.meterbilling.entity.*;
import com.easylinkin.linkappapi.meterbilling.entity.ext.*;
import com.easylinkin.linkappapi.meterbilling.mapper.*;
import com.easylinkin.linkappapi.meterbilling.service.BillingStandardService;
import com.easylinkin.linkappapi.meterbilling.service.RechargeService;
import com.easylinkin.linkappapi.meterbilling.service.RoomExpensesService;
import com.easylinkin.linkappapi.meterbilling.service.RoomManagerService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.webcammanage.util.YYSHDateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import site.morn.util.MessageDigestUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static site.morn.constant.DigestConstant.Algorithms.SPRING_B_CRYPT;

/**
 * class info :
 *
 * @author liuqihang
 * @date 2021/7/8 11:55
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class RoomManagerServiceImpl extends ServiceImpl<RoomInfoMapper, RoomInfo> implements RoomManagerService {

    @Resource
    private RechargeService rechargeService;

    @Resource
    private RoomExpensesService roomExpensesService;

    @Resource
    private RoomBillingRefMapper roomBillingRefMapper;

    @Resource
    private MeterDeviceConfigMapper meterDeviceConfigMapper;

    @Resource
    private RoomTenantryInfoMapper roomTenantryInfoMapper;

    @Resource
    private CommonService commonService;

    @Resource
    private BillingStandardService billingStandardService;

    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;

    @Override
    public String saveRoomInfo(GlobalRoomInfo globalRoomInfo) {
        RoomInfo roomInfo = globalRoomInfo.getRoomInfo();
        RoomTenantryInfo roomTenantryInfo = globalRoomInfo.getRoomTenantryInfo();
        checkRoomInfoNullAttribute(roomInfo);
        checkRoomTenantryInfoNullAttribute(roomTenantryInfo);

        boolean b = checkRoomInfoDuplicateAttribute(new RoomInfo().setRoomCode(roomInfo.getRoomCode()));
        if(b){
            return "房间编码重复";
        }
        boolean b1 = checkRoomInfoDuplicateAttribute(new RoomInfo().setRoomName(roomInfo.getRoomName()).setAreaId(roomInfo.getAreaId()));
        if(b1){
            return "房间名称重复";
        }

        //保存房间信息
        LinkappUser current = linkappUserContextProducer.getCurrent();
        if(current == null){
            throw new IllegalArgumentException("请登录...");
        }
        roomInfo.setTenantId(current.getTenantId());
        commonService.setCreateAndModifyInfo(roomInfo);
        roomInfo.setDeleteStatus(0).setWaterBalance(new BigDecimal(0.0)).setElectricityBalance(new BigDecimal(0.0));
        baseMapper.insert(roomInfo);

        //保存住户合同信息
        roomTenantryInfo.setRoomId(roomInfo.getId())
                .setCreateTime(new Date())
                .setTenantId(current.getTenantId())
                .setDeleteStatus(0)
                .setLockStatus(0).setBindStatus(0);
        roomTenantryInfoMapper.insert(roomTenantryInfo);

        //绑定房间和计费标准关系
        List<Integer> billingIdList = globalRoomInfo.getBillingIdList();
        if(billingIdList != null && billingIdList.size() > 0){
            List<RoomBillingRef> roomBillingRefList = new ArrayList<>();
            billingIdList.forEach(billingId -> {
                RoomBillingRef roomBillingRef = new RoomBillingRef();
                roomBillingRef.setRoomId(roomInfo.getId()).setBillingId(billingId);
                roomBillingRefList.add(roomBillingRef);
            });
            roomBillingRefMapper.batchInsert(roomBillingRefList);
        }
        return null;
    }

    @Override
    public String updateRoomInfo(GlobalRoomInfo globalRoomInfo) {
        RoomInfo roomInfo = globalRoomInfo.getRoomInfo();
        Assert.notNull(roomInfo.getId(), "房间ID不能为空");

        RoomTenantryInfo roomTenantryInfo = globalRoomInfo.getRoomTenantryInfo();
        Assert.notNull(roomTenantryInfo.getId(), "住户ID不能为空");

        checkRoomInfoNullAttribute(roomInfo);
        checkRoomTenantryInfoNullAttribute(roomTenantryInfo);

        boolean b = checkRoomInfoDuplicateAttribute(new RoomInfo().setId(roomInfo.getId()).setRoomCode(roomInfo.getRoomCode()));
        if(b){
            return "房间编码已存在";
        }
        boolean b1 = checkRoomInfoDuplicateAttribute(new RoomInfo().setId(roomInfo.getId()).setRoomName(roomInfo.getRoomName()).setAreaId(roomInfo.getAreaId()));
        if(b1){
            return "房间名称已存在";
        }

        //修改房间信息
        commonService.setModifyInfo(roomInfo);
        baseMapper.updateById(roomInfo);

        //修改住户合同信息
        LinkappUser current = linkappUserContextProducer.getCurrent();
        if(current == null){
            throw new IllegalArgumentException("请登录...");
        }
        RoomTenantryInfo oldRoomTenantryInfo = new RoomTenantryInfo();
        oldRoomTenantryInfo.setId(roomTenantryInfo.getId())
                .setBindStatus(1).setDeleteStatus(1);
        roomTenantryInfoMapper.updateById(oldRoomTenantryInfo);

        roomTenantryInfo.setRoomId(roomInfo.getId())
                .setCreateTime(new Date())
                .setTenantId(current.getTenantId())
                .setDeleteStatus(0)
                .setLockStatus(0).setBindStatus(0);
        roomTenantryInfoMapper.insert(roomTenantryInfo);

        //重新绑定房间和计费标准关系
        List<Integer> billingIdList = globalRoomInfo.getBillingIdList();
        List<RoomBillingRef> roomBillingRefList = new ArrayList<>();
        if(billingIdList != null && billingIdList.size() > 0){
            billingIdList.forEach(billingId -> {
                RoomBillingRef roomBillingRef = new RoomBillingRef();
                roomBillingRef.setRoomId(roomInfo.getId()).setBillingId(billingId);
                roomBillingRefList.add(roomBillingRef);
            });
        }

        QueryWrapper qw = new QueryWrapper();
        qw.eq("room_id", roomInfo.getId());
        roomBillingRefMapper.delete(qw);

        if(roomBillingRefList != null && roomBillingRefList.size() > 0){
            roomBillingRefMapper.batchInsert(roomBillingRefList);
        }
        return null;
    }

    @Override
    public void batchUpdateRoomBilling(BatchUpdateRoom batchUpdateRoom) {
        List<Integer> roomIds = batchUpdateRoom.getRoomIds();
        if(roomIds == null || roomIds.size() <= 0){
            return ;
        }
        QueryWrapper qw = new QueryWrapper();
        qw.in("room_id", roomIds);
        roomBillingRefMapper.delete(qw);

        List<Integer> billingIdList = batchUpdateRoom.getBillingIdList();
        if(billingIdList == null || billingIdList.size() <= 0){
            return ;
        }
        List<RoomBillingRef> roomBillingRefList = new ArrayList<>();
        for (Integer roomId:
                roomIds) {
            billingIdList.forEach(billingId -> {
                RoomBillingRef roomBillingRef = new RoomBillingRef();
                roomBillingRef.setRoomId(roomId).setBillingId(billingId);
                roomBillingRefList.add(roomBillingRef);
            });
        }
        if(roomBillingRefList != null && roomBillingRefList.size() > 0){
            roomBillingRefMapper.batchInsert(roomBillingRefList);
        }
    }

    @Override
    public IPage<RoomList> getRoomPage(Page page, RoomList roomList) {
        LinkappUser current = linkappUserContextProducer.getCurrent();
        if(current == null){
            throw new IllegalArgumentException("请登录...");
        }
        roomList.setTenantId(current.getTenantId());
        return baseMapper.getRoomPage(page, roomList);
    }

    @Override
    public List<WechatRoomList> getRoomListByResident() {
        String phone = linkappUserContextProducer.getCurrentUsername();
        Assert.notNull(phone, "未获取到当前登录用户");
        List<WechatRoomList> roomListByResident = baseMapper.getRoomListByResident(phone);
        return roomListByResident;
    }

    @Override
    public WechatRoomInfo queryRoomData(Integer roomId) {
        //如果roomId == null则默认获取当前住户最新的绑定房间的数据
        if(roomId == null){
            String phone = linkappUserContextProducer.getCurrentUsername();
            Assert.notNull(phone, "未获取到当前登录用户");
            List<WechatRoomList> roomListByResident = baseMapper.getRoomListByResident(phone);
            if(ObjectUtils.isEmpty(roomListByResident)){
                return null;
            }
            roomId = roomListByResident.get(0).getRoomId();
        }
        WechatRoomInfo wechatRoomInfo = new WechatRoomInfo();
        RoomInfo roomInfo = baseMapper.selectById(roomId);
        wechatRoomInfo.setWaterBalance(roomInfo.getWaterBalance());
        wechatRoomInfo.setElectricityBalance(roomInfo.getElectricityBalance());

        //获取房间绑定设备
        QueryWrapper qw = new QueryWrapper();
        qw.eq("delete_status","0");
        qw.eq("room_id",roomId);
        List<MeterDeviceConfig> list = meterDeviceConfigMapper.selectList(qw);

        Date[] settlementDate = new Date[2];
        settlementDate[0] = DateUtil.getDateFromYYYYMMDD(YYSHDateUtil.getFirstDayOfMonth());
        settlementDate[1] = new Date();
        List<EnergyConsumption> energyConsumptionDateList = roomExpensesService.getEnergyConsumptionDateListNew(settlementDate, list);
        if(ObjectUtils.isEmpty(energyConsumptionDateList)){
            wechatRoomInfo.setMonthElectricityAmount(new BigDecimal(0.0));
            wechatRoomInfo.setMonthWaterAmount(new BigDecimal(0.0));
        }else {
            energyConsumptionDateList.forEach(energyConsumption -> {
                if(energyConsumption.getMeterType().equals(0)){
                    wechatRoomInfo.setMonthWaterAmount(energyConsumption.getAmount());
                }else if(energyConsumption.getMeterType().equals(1)){
                    wechatRoomInfo.setMonthElectricityAmount(energyConsumption.getAmount());
                }else {
                    wechatRoomInfo.setMonthElectricityAmount(new BigDecimal(0.0));
                    wechatRoomInfo.setMonthWaterAmount(new BigDecimal(0.0));
                }
            });
        }
        return wechatRoomInfo;
    }

    @Override
    public void export(RoomList roomList, HttpServletRequest request, HttpServletResponse response) {
        List<RoomList> roomPage = null;
        if(roomList.getRoomIdList() != null && roomList.getRoomIdList().size() > 0){
            roomPage = baseMapper.getRoomdataByIds(roomList);
        }else {
            IPage<RoomList> roomPage1 = getRoomPage(new Page().setCurrent(1).setSize(10000), roomList);
            roomPage = roomPage1.getRecords();
        }
        Assert.notEmpty(roomPage,"无数据");

        List<RoomExcel> roomExcelList = parseExcelData(roomPage);
        String keyValue = "房号编码:roomCode,房间:roomName,住户:name,手机号码:phone,合同期限:contractLimit,水量单价:waterPrice,电量单价:electricityPrice,钱包余额:balance";
        String title = "房间管理数据";
        String fileName = title + ".xls";
        try {
            List<String> stringList = new ArrayList<String>();
            OutputStream outputStream = OutputStreamUtil
                    .getOutputStream(request, response, fileName);
            ExcelTools.exportBankExcelV2(outputStream, keyValue, roomExcelList, ExcelConstant.XLS, title, stringList);
            response.flushBuffer();
            outputStream.close();
        } catch (IOException e) {
            log.error("excel导出失败");
            throw new RuntimeException("excel导出失败！IOException异常" + e.getMessage());
        } catch (Exception e) {
            log.error("excel导出失败");
            throw new RuntimeException("excel导出失败！" + e.getMessage());
        }
    }

    @Resource
    private ExpensesTimerTaskMapper expensesTimerTaskMapper;

    @Override
    public void deleteTimerTask() {
        QueryWrapper qw = new QueryWrapper();
        expensesTimerTaskMapper.delete(qw);
    }

    private List<RoomExcel> parseExcelData(List<RoomList> roomPage){
        List<RoomExcel> roomExcelList = new ArrayList<>();

        roomPage.forEach(room -> {
            BigDecimal waterPrice = new BigDecimal(0.0);
            BigDecimal electricityPrice = new BigDecimal(0.0);
            String waterUnit = "吨";
            String electricityUnit = "度";

            List<BaseBilling> meterPriceList = room.getMeterPriceList();
            for (BaseBilling baseBilling:
                meterPriceList) {
                if(baseBilling.getMeterType().equals(0)){
                    waterPrice = waterPrice.add(baseBilling.getPrice());
                    waterUnit = baseBilling.getUnit();
                }else if(baseBilling.getMeterType().equals(1)){
                    electricityPrice = electricityPrice.add(baseBilling.getPrice());
                    electricityUnit = baseBilling.getUnit();
                }
            }
            String waterPriceResult = waterPrice.toString() + "/" + waterUnit;
            String electricityPriceResult = electricityPrice.toString() + "/" + electricityUnit;


            RoomExcel roomExcel = RoomExcel.builder()
                    .roomCode(room.getRoomCode())
                    .roomName(room.getRoomName())
                    .name(room.getName())
                    .phone(room.getPhone())
                    .contractLimit(DateUtil.format(room.getContractStartTime(), DateUtil.DATE_TIME_FORMAT_DAY) + "~" + DateUtil.format(room.getContractEndTime(), DateUtil.DATE_TIME_FORMAT_DAY))
                    .waterPrice(waterPriceResult)
                    .electricityPrice(electricityPriceResult)
                    .balance("水费:" + room.getWaterBalance().toString() + "; 电费:" + room.getElectricityBalance().toString()).build();
            roomExcelList.add(roomExcel);
        });
        return roomExcelList;
    }

    @Override
    public GlobalRoomInfo getGlobalRoomInfo(Integer roomId) {
        GlobalRoomInfo globalRoomInfo = new GlobalRoomInfo();
        RoomInfo roomInfo = baseMapper.selectById(roomId);
        if(roomInfo != null){
            globalRoomInfo.setRoomInfo(roomInfo);
        }

        QueryWrapper qw = new QueryWrapper();
        qw.eq("room_id", roomId);
        qw.eq("delete_status", 0);
        qw.eq("bind_status", 0);
        List<RoomTenantryInfo> roomTenantryInfoList = roomTenantryInfoMapper.selectList(qw);
        if(roomTenantryInfoList != null && roomTenantryInfoList.size() > 0){
            globalRoomInfo.setRoomTenantryInfo(roomTenantryInfoList.get(0));
        }

        QueryWrapper qw2 = new QueryWrapper();
        qw2.eq("room_id", roomId);
        List<RoomBillingRef> list = roomBillingRefMapper.selectList(qw2);
        if(list != null && list.size() > 0){
            List<BaseBilling> baseBillingList = new ArrayList<>();
            for (RoomBillingRef roomBillingRef:
                    list) {
                BaseBilling baseBilling = billingStandardService.getBillingStandardInfoById(roomBillingRef.getBillingId());
                baseBillingList.add(baseBilling);
            }
            globalRoomInfo.setBaseBillingList(baseBillingList);
        }
        return globalRoomInfo;
    }

    @Override
    public void delete(Integer roomId) {
        RoomInfo roomInfo = baseMapper.selectById(roomId);
        if(roomInfo != null){
            BigDecimal waterBalance = null;
            BigDecimal electricityBalance = null;
            if((roomInfo.getWaterBalance().compareTo(new BigDecimal(0.0)) > 0)){
                waterBalance = roomInfo.getWaterBalance();
            }
            if((roomInfo.getElectricityBalance().compareTo(new BigDecimal(0.0)) > 0)){
                electricityBalance = roomInfo.getElectricityBalance();
            }
            Object[] objects = rechargeService.deductionBalanceForDeleteRoom(roomId, waterBalance, electricityBalance);
            if(!(Boolean)objects[0]){
                throw new IllegalArgumentException((String)objects[1]);
            }
        }

        //删除房间
        QueryWrapper qw = new QueryWrapper();
        qw.eq("id", roomId);
        qw.eq("delete_status", 0);
        baseMapper.update(new RoomInfo().setDeleteStatus(1).setModifyTime(new Date()), qw);

        //删除合同
        QueryWrapper qw2 = new QueryWrapper();
        qw2.eq("room_id", roomId);
        qw2.eq("delete_status", 0);
        roomTenantryInfoMapper.update(new RoomTenantryInfo().setDeleteStatus(1), qw2);

        //删除房间和计费标准关联
        QueryWrapper qw3 = new QueryWrapper();
        qw3.eq("room_id", roomId);
        roomBillingRefMapper.delete(qw3);

        //删除仪表设备房间关联
        QueryWrapper qw4 = new QueryWrapper();
        qw4.eq("room_id", roomId);
        qw4.eq("delete_status", 0);
        MeterDeviceConfig meterDeviceConfig = new MeterDeviceConfig();
        meterDeviceConfig.setDeleteStatus(1);
        meterDeviceConfig.setModifyTime(LocalDateTime.now());
        meterDeviceConfigMapper.update(meterDeviceConfig, qw4);
    }

    public void checkRoomInfoNullAttribute(RoomInfo roomInfo){
        Assert.notNull(roomInfo.getRoomName(), "房间名称不能为空");
        Assert.notNull(roomInfo.getRoomCode(), "房间编码不能为空");
        Assert.notNull(roomInfo.getAreaId(), "房间所属空间不能为密码空");
    }

    public void checkRoomTenantryInfoNullAttribute(RoomTenantryInfo roomTenantryInfo){
        Assert.notNull(roomTenantryInfo.getContractStartTime(), "合同开始时间不能为空");
        Assert.notNull(roomTenantryInfo.getContractEndTime(), "合同结束时间不能为空");
    }

    /**
     * 验证房间属性重复值
     * @param roomInfo
     * @return  true:重复，false:正常
     */
    private boolean checkRoomInfoDuplicateAttribute(RoomInfo roomInfo){
        QueryWrapper qw = new QueryWrapper();
        qw.eq("delete_status", 0);
        if(roomInfo.getRoomName() != null){
            qw.eq("room_name", roomInfo.getRoomName());
        }
        if(roomInfo.getRoomCode() != null){
            qw.eq("room_code", roomInfo.getRoomCode());
        }
        if(roomInfo.getAreaId() != null){
            qw.eq("area_id", roomInfo.getAreaId());
        }
        if(roomInfo.getId() != null){
            qw.notIn("id", roomInfo.getId());
        }
        Integer count = baseMapper.selectCount(qw);
        if(count != null && count > 0){
            return true;
        }
        return false;
    }


}
